package cn.lingyangwl.agile.ram;

import cn.lingyangwl.agile.ram.model.ResourceSyncResp;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author shenguangyang
 */
@Slf4j
@Service
public class RamResourceInit implements InitializingBean, ApplicationContextAware,
        ApplicationListener<ApplicationStartedEvent> {
    private ApplicationContext applicationContext;

    public static final Set<ResourceSyncResp> resourceList = new HashSet<>();

    private static final PathMatcher pathMatcher = new AntPathMatcher();


    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, RequestMappingHandlerMapping> beansOfType = applicationContext.getBeansOfType(RequestMappingHandlerMapping.class);
        // key = action
        Map<String, ResourceSyncResp> personalResourceMap = new ConcurrentHashMap<>();
        beansOfType.values().forEach(e -> {

            Map<RequestMappingInfo, HandlerMethod> map = e.getHandlerMethods();
            map.keySet().forEach(info -> {
                HandlerMethod handlerMethod = map.get(info);
                RamPersonalResource classAnnotation = handlerMethod.getBeanType().getAnnotation(RamPersonalResource.class);
                if (Objects.nonNull(classAnnotation)) {
                    processResource(classAnnotation, personalResourceMap);
                }

                // 判断方法上是否有打该注解 || 判断类上是否有打该注解
                RamResource ramResource = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), RamResource.class);
                if (Objects.nonNull(ramResource)) {
                    processResource(ramResource, info);
                }
            });
        });

        resourceList.addAll(personalResourceMap.values());
    }

    private void processResource(RamResource ramResource, RequestMappingInfo info) {
        String action = ramResource.action();
        String name = ramResource.name();
        ActionType actionType = ramResource.type();
        if (StringUtils.isNotEmpty(action)) {
            // action 格式: system:user:query
            action = action.replace(" ", "");

            if (StringUtils.isEmpty(name)) {
                name = action;
            }

            String[] actionSplit = action.split(":");
            if (actionSplit.length != 3) {
                throw new BizException("action [{}] format error, eg: system:user:query", action, RamResource.class.getSimpleName());
            }
            String moduleCode = actionSplit[0];
            List<String> mappingPath = RequestMappingUtils.getMappingPath(ramResource, info);

            for (String path : mappingPath) {
                ResourceSyncResp resourceSync = ResourceSyncResp.builder()
                        .action(action).url(path).name(name).moduleCode(moduleCode).actionType(actionType.getCode())
                        .isPersonal(false).build();
                resourceList.add(resourceSync);
            }
        }
    }

    private void processResource(RamPersonalResource ramResource, Map<String, ResourceSyncResp> personalResourceMap) {
        String action = ramResource.action();
        String name = ramResource.name();
        if (StringUtils.isEmpty(ramResource.url())) {
            throw new BizException("{} class url is null", ramResource.getClass().getName());
        }
        String url = ramResource.url();;
        ActionType actionType = ramResource.type();

        if (StringUtils.isNotEmpty(action)) {
            // action 格式: system:user:query
            action = action.replace(" ", "");

            String[] actionSplit = action.split(":");
            if (actionSplit.length != 3) {
                throw new BizException("action [{}] format error, eg: system:user:query", action, RamResource.class.getSimpleName());
            }

            if (StringUtils.isEmpty(name)) {
                name = action;
            }

            String moduleCode = actionSplit[0];

            ResourceSyncResp resourceSync = ResourceSyncResp.builder()
                    .action(action).url( url + "/**").name(name).moduleCode(moduleCode)
                    .actionType(actionType.getCode())
                    .isPersonal(true).build();
            personalResourceMap.put(resourceSync.getAction(), resourceSync);
        }
    }

    @Override
    @SuppressWarnings("all")
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    @SuppressWarnings("all")
    public void onApplicationEvent(ApplicationStartedEvent event) {
        // 发送到消息队列中
//        resourceList.stream().parallel().forEach(e -> {
//            WorkspaceContentHolder.get().setAppId(TenantCons.ADMIN_APP_ID);
//            RamResourceMQ msg = RamResourceMQ.build(e);
//            rabbitTemplate.convertAndSend(RamResourceMQ.EXCHANGE, RamResourceMQ.KEY, msg.toMessage());
//        });
    }
}
